package com.bn.commerce.order.purchase;

import java.beans.IntrospectionException;
import java.io.IOException;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpSession;
import javax.transaction.TransactionManager;

import atg.commerce.CommerceException;
import atg.commerce.order.CommerceItem;
import atg.commerce.order.HardgoodShippingGroup;
import atg.commerce.order.ShippingGroup;
import atg.commerce.order.ShippingGroupRelationship;
import atg.commerce.order.ShippingGroupRelationshipContainerImpl;
import atg.core.util.StringUtils;
import atg.droplet.DropletFormException;
import atg.dtm.TransactionDemarcation;
import atg.dtm.TransactionDemarcationException;
import atg.projects.store.order.purchase.ShippingInfoFormHandler;
import atg.repository.RepositoryItem;
import atg.service.pipeline.RunProcessException;
import atg.servlet.DynamoHttpServletRequest;
import atg.servlet.DynamoHttpServletResponse;
import atg.userprofiling.address.AddressTools;

import com.bn.commerce.order.BNCommerceItemImpl;
import com.bn.commerce.order.BNOrderImpl;
import com.bn.commerce.order.BNOrderTools;
import com.bn.commerce.order.BnGiftWrapCommerceItemImpl;
import com.bn.userprofile.BNProfileTools;
import com.bn.util.BNContactInfo;

public class BNShippingInfoFormHandler extends ShippingInfoFormHandler {

	private BNContactInfo shipContactInfo;
	private boolean needTaxExemption;
	private String updateAddressSuccessURL;
	private String updateAddressErrorURL;
	private String removeShippingAddressSuccessURL;
	private String removeShippingAddressErrorURL;
	private String shippingNickName;
	private BNProfileTools profileTools;
	private boolean isMakeDefault;
	private boolean saveAddressToProfile;
	private boolean setAsDefaultAddress;
	private String deliveryPreference;
	private String addShippingMethodSuccessURL;
	private String addShippingMethodErrorURL;
	private String addShippingAddressSuccessURL;
	private String addShippingAddressErrorURL;

	public BNShippingInfoFormHandler(){
		shipContactInfo= new BNContactInfo();
	}

	@Override
	public void preAddShippingAddress(DynamoHttpServletRequest pRequest,
			DynamoHttpServletResponse pResponse) throws ServletException,
			IOException {
		vlogDebug("preAddShippingAddress");
		if(StringUtils.isEmpty(shipContactInfo.getFirstName())){
			addFormException(new DropletFormException("missingFirstNameField", ""));
		}
		if(StringUtils.isEmpty(shipContactInfo.getLastName())){
			addFormException(new DropletFormException("missingLastNameField", ""));
		}
		if(StringUtils.isEmpty(shipContactInfo.getCountry())){
			addFormException(new DropletFormException("missingCountryField", ""));
		}
		if(StringUtils.isEmpty(shipContactInfo.getAddress1())){
			addFormException(new DropletFormException("missingAddress1Field", ""));
		}
		if(StringUtils.isEmpty(shipContactInfo.getAddress2())){
			addFormException(new DropletFormException("missingAddress2Field", ""));
		}
		if(StringUtils.isEmpty(shipContactInfo.getCompanyName())){
			addFormException(new DropletFormException("missingComapnyNameField", ""));
		}
		if(StringUtils.isEmpty(shipContactInfo.getCity())){
			addFormException(new DropletFormException("missingCityField", ""));
		}
		if(StringUtils.isEmpty(shipContactInfo.getState())){
			addFormException(new DropletFormException("missingStateField", ""));
		}
		if(StringUtils.isEmpty(shipContactInfo.getPostalCode())){
			addFormException(new DropletFormException("missingPostalCode", ""));
		}
		if(StringUtils.isEmpty(shipContactInfo.getPhoneNumber())){
			addFormException(new DropletFormException("missingPhoneNumberField", ""));
		}
		if(StringUtils.isEmpty(shipContactInfo.getEmail())){
			addFormException(new DropletFormException("missingEmailField", ""));
		}
	}

	/**
	 * Adds shiiping adress
	 */
	public boolean handleAddShippingAddress(DynamoHttpServletRequest dRequest, DynamoHttpServletResponse dResponse)
			throws ServletException, IOException {

			preAddShippingAddress (dRequest,dResponse);
			vlogDebug("Entry create EditShippingAddress item");
			vlogDebug("shippingContactInfo  - getFirstName : "+shipContactInfo.getFirstName());
			vlogDebug("shippingContactInfo  - getLastName : "+shipContactInfo.getLastName());
			vlogDebug("shippingContactInfo  - getCountry : "+shipContactInfo.getCountry());
			vlogDebug("shippingContactInfo  - getAddress1 : "+shipContactInfo.getAddress1());
			vlogDebug("shippingContactInfo 	- getAddress2 : "+shipContactInfo.getAddress2());
			vlogDebug("shippingContactInfo  - getCompanyName : "+shipContactInfo.getCompanyName());
			vlogDebug("shippingContactInfo  - getCity : "+shipContactInfo.getCity());
			vlogDebug("shippingContactInfo  - getState : "+shipContactInfo.getState());
			vlogDebug("shippingContactInfo  - getPostalCode : "+shipContactInfo.getPostalCode());
			vlogDebug("shippingContactInfo  - getPhoneNumber :  "+shipContactInfo.getPhoneNumber());

			TransactionManager tm = getTransactionManager();
			TransactionDemarcation td = getTransactionDemarcation();
			String nickName = "";

			try {

				if (tm != null) {
					td.begin(tm, 3);
				}
				if (getOrder() == null)
					formatAndAddErrorMessage("noOrderToModify", "order", dRequest, dResponse);
				if (getFormError()) {
					return checkFormRedirect(getAddShippingAddressSuccessURL(),getAddShippingAddressErrorURL(), dRequest, dResponse);
				}
				synchronized (getOrder()) {
					try {
						ShippingGroup sg = (ShippingGroup) getOrder().getShippingGroups().get(0);
						if(sg instanceof HardgoodShippingGroup){
							((HardgoodShippingGroup) sg).setShippingAddress(shipContactInfo);

							if(isSaveAddressToProfile() || isSetAsDefaultAddress()){
								/* If user is logged in, then user entered new address set to profile. */
								BNPurchaseProcessorHelper bnPurchaseProcessHelper = (BNPurchaseProcessorHelper)getPurchaseProcessHelper();
								if(bnPurchaseProcessHelper.isUserLoggedIn(getProfile())){
									BNOrderTools orderTools = (BNOrderTools) (getOrderManager().getOrderTools());
									BNProfileTools bnProfileTools =(BNProfileTools)getProfileTools();
									String shippingAddressID = (String)bnProfileTools.isAddressExists(getProfile(), getShipContactInfo());
									if(null!=shippingAddressID){
										RepositoryItem addressItem = bnProfileTools.getProfileAddressById(shippingAddressID);
										try {
											AddressTools.copyAddress(shipContactInfo, addressItem);
										} catch (IntrospectionException e) {
											vlogError("Exception while updating profile address"+e.getMessage());
										}
									}else {
										 nickName = orderTools.saveAddressToAddressBook(getProfile(), getShipContactInfo(), getShippingNickName(),isMakeDefault());
									}
								}
								if(isSetAsDefaultAddress()){
									profileTools.setDefaultShippingAddress(getProfile(), nickName);
								}
							}
						}
					} catch (Exception e) {
						if (isLoggingError())
							logError("Can't end transaction ", e);
					}
				}

			} catch (TransactionDemarcationException e) {
				vlogError("BNShippingInfoFormHandler: handleAddShippingAddress: TransactionDemarcationException", e);
				if (e.getMessage() != null) {
					addFormException(new DropletFormException(e.getMessage(), "", ""));
				}
				dResponse.sendLocalRedirect(getUpdateAddressErrorURL(), dRequest);
			} finally {
				try {
					if (tm != null)
						td.end();
				} catch (TransactionDemarcationException e) {
					if (isLoggingError())
						logError("Can't end transaction ", e);
				}
			}
			return checkFormRedirect(getAddShippingAddressSuccessURL(),getAddShippingAddressErrorURL(), dRequest, dResponse);
		}




	/**
	 * get selected shipping address and add
	 */
	public boolean handleAddSelectedShippingAddress(DynamoHttpServletRequest dRequest, DynamoHttpServletResponse dResponse)
			throws ServletException, IOException {

			TransactionManager tm = getTransactionManager();
			TransactionDemarcation td = getTransactionDemarcation();

			try {

				if (tm != null) {
					td.begin(tm, 3);
				}
				if (getOrder() == null)
					formatAndAddErrorMessage("noOrderToModify", "order", dRequest, dResponse);
				if (getFormError()) {
					return checkFormRedirect(getUpdateAddressSuccessURL(), getUpdateAddressErrorURL(), dRequest, dResponse);
				}
				synchronized (getOrder()) {
					try {
						selectShippingAddress ();
					} catch (Exception e) {
						if (isLoggingError())
							logError("Can't end transaction ", e);
					}
				}

			} catch (TransactionDemarcationException e) {
				vlogError("BNShippingInfoFormHandler: handleAddShippingAddress: TransactionDemarcationException", e);
				if (e.getMessage() != null) {
					addFormException(new DropletFormException(e.getMessage(), "", ""));
				}
				dResponse.sendLocalRedirect(getUpdateAddressErrorURL(), dRequest);
			} finally {
				try {
					if (tm != null)
						td.end();
				} catch (TransactionDemarcationException e) {
					if (isLoggingError())
						logError("Can't end transaction ", e);
				}
			}
			return checkFormRedirect(getUpdateAddressSuccessURL(), getUpdateAddressErrorURL(), dRequest, dResponse);
		}

	public boolean handleProcessDeliveryPreference(DynamoHttpServletRequest dRequest, DynamoHttpServletResponse dResponse)
			throws ServletException, IOException {

			TransactionManager tm = getTransactionManager();
			TransactionDemarcation td = getTransactionDemarcation();

			try {

				if (tm != null) {
					td.begin(tm, 3);
				}
				if (getOrder() == null)
					formatAndAddErrorMessage("noOrderToModify", "order", dRequest, dResponse);
				if (getFormError()) {
					return checkFormRedirect(getAddShippingMethodSuccessURL(), getAddShippingMethodErrorURL(),dRequest, dResponse);
				}

				synchronized (getOrder()) {
					String deliveryPrefs = getDeliveryPreference();
					ShippingGroup sg = (ShippingGroup) getOrder().getShippingGroups().get(0);
					if(sg instanceof HardgoodShippingGroup){
						((HardgoodShippingGroup) sg).setShippingMethod(deliveryPrefs);
					}
					repriceOrder(dRequest, dResponse);
				}

			} catch (TransactionDemarcationException e) {
				vlogError("BNShippingInfoFormHandler: handleAddShippingAddress: TransactionDemarcationException", e);
				if (e.getMessage() != null) {
					addFormException(new DropletFormException(e.getMessage(), "", ""));
				}
				dResponse.sendLocalRedirect(getUpdateAddressErrorURL(), dRequest);
			} finally {
				try {
					if (tm != null)
						td.end();
				} catch (TransactionDemarcationException e) {
					if (isLoggingError())
						logError("Can't end transaction ", e);
				}
			}
			return checkFormRedirect(getAddShippingMethodSuccessURL(), getAddShippingMethodErrorURL(),dRequest, dResponse);
		}



	private void selectShippingAddress() {
		try {
			if(!StringUtils.isBlank( getShippingNickName())) {
				RepositoryItem addressItem = getProfileTools().getProfileAddress(getProfile(), getShippingNickName());
				shipContactInfo = (BNContactInfo)AddressTools.copyAddress(addressItem, getShipContactInfo());
				setShipContactInfo(shipContactInfo);
				ShippingGroup sg = (ShippingGroup) getOrder().getShippingGroups().get(0);
				if(sg instanceof HardgoodShippingGroup){
					((HardgoodShippingGroup) sg).setShippingAddress(getShipContactInfo());
				}
			}
		} catch (IntrospectionException e) {
			if (isLoggingError()) {
                logError("Error while adding shipping address", e);
			}
		}
	}

	/**
	 * Checks if session is valid
	 * @param request
	 * @return
	 */
	private boolean isSessionValid(DynamoHttpServletRequest request) {
		boolean valid = true;
		HttpSession session = request.getSession();
		if (session == null || session.isNew())
			valid = false;
		if (!request.isRequestedSessionIdValid())
			valid = false;
		return valid;
	}

	protected TransactionDemarcation getTransactionDemarcation() {
		return new TransactionDemarcation();
	}

	/**
	 * @return the needTaxExemption
	 */
	public boolean isNeedTaxExemption() {
		return needTaxExemption;
	}

	/**
	 * Formats and finds the error message for the supplied key
	 * @param errorKey
	 * @param property
	 * @param request
	 * @param response
	 * @throws ServletException
	 * @throws IOException
	 */
	public void formatAndAddErrorMessage(String errorKey, String property, DynamoHttpServletRequest request, DynamoHttpServletResponse response)
			throws ServletException, IOException {
		String msg = formatUserMessage(errorKey, request, response);
		String propertyPath = generatePropertyPath(property);
		addFormException(new DropletFormException(msg, propertyPath, errorKey));
	}

	public String getUpdateAddressSuccessURL() {
		return updateAddressSuccessURL;
	}

	public void setUpdateAddressSuccessURL(String updateAddressSuccessURL) {
		this.updateAddressSuccessURL = updateAddressSuccessURL;
	}

	public String getUpdateAddressErrorURL() {
		return updateAddressErrorURL;
	}

	public void setUpdateAddressErrorURL(String updateAddressErrorURL) {
		this.updateAddressErrorURL = updateAddressErrorURL;
	}
	public BNContactInfo getShipContactInfo() {
		return shipContactInfo;
	}
	public void setShipContactInfo(BNContactInfo shipContactInfo) {
		this.shipContactInfo = shipContactInfo;
	}



	public String getRemoveShippingAddressSuccessURL() {
		return removeShippingAddressSuccessURL;
	}



	public void setRemoveShippingAddressSuccessURL(
			String removeShippingAddressSuccessURL) {
		this.removeShippingAddressSuccessURL = removeShippingAddressSuccessURL;
	}



	public String getRemoveShippingAddressErrorURL() {
		return removeShippingAddressErrorURL;
	}



	public void setRemoveShippingAddressErrorURL(
			String removeShippingAddressErrorURL) {
		this.removeShippingAddressErrorURL = removeShippingAddressErrorURL;
	}

	public String getShippingNickName() {
		return shippingNickName;
	}

	public void setShippingNickName(String shippingNickName) {
		this.shippingNickName = shippingNickName;
	}

	public BNProfileTools getProfileTools() {
		return profileTools;
	}

	public void setProfileTools(BNProfileTools profileTools) {
		this.profileTools = profileTools;
	}

	public boolean isMakeDefault() {
		return isMakeDefault;
	}

	public void setMakeDefault(boolean isMakeDefault) {
		this.isMakeDefault = isMakeDefault;
	}

	public boolean isSaveAddressToProfile() {
		return saveAddressToProfile;
	}

	public void setSaveAddressToProfile(boolean saveAddressToProfile) {
		this.saveAddressToProfile = saveAddressToProfile;
	}

	public boolean isSetAsDefaultAddress() {
		return setAsDefaultAddress;
	}

	public void setSetAsDefaultAddress(boolean setAsDefaultAddress) {
		this.setAsDefaultAddress = setAsDefaultAddress;
	}

	public String getDeliveryPreference() {
		return deliveryPreference;
	}

	public void setDeliveryPreference(String deliveryPreference) {
		this.deliveryPreference = deliveryPreference;
	}

	public String getAddShippingMethodSuccessURL() {
		return addShippingMethodSuccessURL;
	}

	public void setAddShippingMethodSuccessURL(String addShippingMethodSuccessURL) {
		this.addShippingMethodSuccessURL = addShippingMethodSuccessURL;
	}

	public String getAddShippingMethodErrorURL() {
		return addShippingMethodErrorURL;
	}

	public void setAddShippingMethodErrorURL(String addShippingMethodErrorURL) {
		this.addShippingMethodErrorURL = addShippingMethodErrorURL;
	}

	public String getAddShippingAddressSuccessURL() {
		return addShippingAddressSuccessURL;
	}

	public void setAddShippingAddressSuccessURL(String addShippingAddressSuccessURL) {
		this.addShippingAddressSuccessURL = addShippingAddressSuccessURL;
	}

	public String getAddShippingAddressErrorURL() {
		return addShippingAddressErrorURL;
	}

	public void setAddShippingAddressErrorURL(String addShippingAddressErrorURL) {
		this.addShippingAddressErrorURL = addShippingAddressErrorURL;
	}


}
